package com.songlanyun.modules.coupon.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.songlanyun.common.enums.CouponConstant;
import com.songlanyun.common.enums.GoodsConstant;
import com.songlanyun.common.enums.MarketingConstant;
import com.songlanyun.common.exception.RRException;
import com.songlanyun.common.utils.BeanUtil;
import com.songlanyun.common.utils.custom.ClassConvertUtils;
import com.songlanyun.common.validator.ValidatorUtils;
import com.songlanyun.modules.coupon.entity.CouponGoodsEntity;
import com.songlanyun.modules.coupon.entity.CouponShopEntity;
import com.songlanyun.modules.coupon.model.dto.CouponEntityDTO;
import com.songlanyun.modules.coupon.model.vo.AdaptActivityVo;
import com.songlanyun.modules.coupon.model.vo.CouponEntityVo;
import com.songlanyun.modules.coupon.service.CouponGoodsService;
import com.songlanyun.modules.coupon.service.CouponShopService;
import com.songlanyun.modules.goods.entity.Goods;
import com.songlanyun.modules.goods.entity.GoodsAuthShop;
import com.songlanyun.modules.coupon.model.dto.CouponPageReq;
import com.songlanyun.modules.goods.service.GoodsService;
import com.songlanyun.modules.shop.entity.ShopEntity;
import com.songlanyun.modules.shop.service.ShopService;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.songlanyun.common.utils.PageUtils;
import com.songlanyun.common.utils.Query;

import com.songlanyun.modules.coupon.dao.CouponDao;
import com.songlanyun.modules.coupon.entity.CouponEntity;
import com.songlanyun.modules.coupon.service.CouponService;
import org.springframework.transaction.annotation.Transactional;


@Service("couponService")
public class CouponServiceImpl extends ServiceImpl<CouponDao, CouponEntity> implements CouponService {

    @Autowired
    private CouponGoodsService couponGoodsService;

    @Autowired
    private CouponShopService couponShopService;


    @Autowired
    private ShopService shopService;

    @Autowired
    private GoodsService goodsService;


    @Override
    public CouponEntity create(CouponEntity entity) {
        this.baseMapper.insert(entity);
        return entity;
    }

    @Override
    public CouponEntity modify(CouponEntity entity) {
        this.baseMapper.updateById(entity);
        return entity;
    }

    @Override
    public void remove(Long id) {

    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {

        IPage<CouponEntityVo> page = this.baseMapper.queryCouponPage(new Query<CouponEntityVo>().getPage(params), paramsMapToReq(params));

        return new PageUtils(page);
    }

    @Override
    public PageUtils canReceivePage(Map<String, Object> params) {
        params.put("status",3);
        IPage<CouponEntityVo> page = this.baseMapper.queryCouponPage(new Query<CouponEntityVo>().getPage(params), paramsMapToReq(params));

        return new PageUtils(page);
    }

    private CouponPageReq paramsMapToReq(Map<String, Object> params) {
        CouponPageReq req = new CouponPageReq();
        String shopId = MapUtil.getStr(params, "shop_id");
        if (StringUtils.isNotEmpty(shopId)) {
            req.setShopId(ClassConvertUtils.objToLong(shopId));
        }
        String name = MapUtil.getStr(params, "name");
        if (StringUtils.isNotEmpty(name)) {
            req.setName(name);
        }

        Integer mode = MapUtil.getInt(params, "mode");
        if (!ObjectUtils.isNull(mode) && mode>=-1) {
            req.setMode(mode);
        }

        Integer trait = MapUtil.getInt(params, "trait");
        if (!ObjectUtils.isNull(trait) && trait>=-1) {
            req.setTrait(trait);
        }

        Integer status = MapUtil.getInt(params, "status");
        if (!ObjectUtils.isNull(status) && status>=-1) {
            req.setStatus(status);
        }

        Date startTime = MapUtil.getDate(params, "start_time");
        if (!ObjectUtils.isNull(startTime)) {
            req.setStartTime(startTime);
        }

        Date endTime = MapUtil.getDate(params, "end_time");
        if (!ObjectUtils.isNull(endTime)) {
            req.setEndTime(endTime);
        }
        if(!ObjectUtils.isNull(req.getStartTime()) && !ObjectUtils.isNull(req.getEndTime()))
        {
            if(DateUtil.compare(req.getStartTime(),req.getEndTime())>=0)
            {
                throw new RRException("开始时间必须小于结束时间");
            }
        }
        return req;

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CouponEntity add(CouponEntityDTO dto) {
        ValidatorUtils.validateEntity(dto);
        validateMode(dto);
        Integer adaptActivity = computeAdaptActivity(dto);

        if(DateUtil.compare(dto.getStartTime(),dto.getEndTime())>=0)
        {
            throw new RRException("开始的时间不能晚于结束时间");
        }
        Date now = new Date();
        if(DateUtil.compare(now,dto.getStartTime())>0)
        {
            throw new RRException("开始的时间必须晚于当前时间");
        }

        if(dto.getIssueNumber()!=-1)
        {
            if(dto.getReceiveLimit()>dto.getIssueNumber())
            {
                throw new RRException("每人限领数不能超过发行量");
            }
        }


        CouponEntity couponEntity = new CouponEntity();
        BeanUtil.copyPropertiesIgnoreNull(dto,couponEntity);
        Date date = new Date();
        String dStr = DateUtil.format(date, "yyyyMMddHHmmss");
        couponEntity.setCode("LM"+dStr+RandomUtil.randomInt(100, 999));
        couponEntity.setAdaptActivity(adaptActivity);
        couponEntity.setReceiveNum(0);
        couponEntity.setMode(CouponConstant.CouponMode.getByCode(dto.getMode()));
        couponEntity.setTrait(CouponConstant.CouponTrait.getByCode(dto.getTrait()));
        this.create(couponEntity);

        batchAdaptShopOrGoods(dto, couponEntity);

        return couponEntity;

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CouponEntity edit(CouponEntityDTO dto) {
        CouponEntity couponEntity = this.loadById(dto.getId(), true);
        ValidatorUtils.validateEntity(dto);
        validateMode(dto);
        Integer adaptActivity = computeAdaptActivity(dto);

        Date now = new Date();
        if(DateUtil.compare(now,couponEntity.getStartTime())>0)
        {
            throw new RRException("优惠券活动已开始不能修改");
        }

        if(DateUtil.compare(now,dto.getStartTime())>0)
        {
            throw new RRException("开始的时间必须晚于当前时间");
        }

        if(DateUtil.compare(dto.getStartTime(),dto.getEndTime())>=0)
        {
            throw new RRException("开始的时间不能晚于结束时间");
        }


        BeanUtil.copyPropertiesIgnoreNull(dto,couponEntity);
        couponEntity.setAdaptActivity(adaptActivity);
        couponEntity.setMode(CouponConstant.CouponMode.getByCode(dto.getMode()));
        couponEntity.setTrait(CouponConstant.CouponTrait.getByCode(dto.getTrait()));
        this.modify(couponEntity);


        batchAdaptShopOrGoods(dto, couponEntity);
        return couponEntity;
    }



    @Override
    public void released(Long id, Long shopId) {
        CouponEntity couponEntity = this.loadById(id, true);
        if(CouponConstant.CouponMode.SHOP.equals(couponEntity.getMode()))
        {
            if(!couponEntity.getShopId().equals(shopId))
            {
                throw new RRException("只能发布自己店铺的优惠券");
            }
        }

        if(!CouponConstant.UseStatus.WAIT_RELEASE.equals(couponEntity.getActiveState()))
        {
            throw new RRException("只有待发布的优惠券才可以发布");
        }

        couponEntity.setStatus(CouponConstant.CouponStatus.RELEASED);
        this.modify(couponEntity);
    }


    @Override
    public void stop(Long id, Long shopId) {
        CouponEntity couponEntity = this.loadById(id, true);
        if(CouponConstant.CouponMode.SHOP.equals(couponEntity.getMode()))
        {
            if(!couponEntity.getShopId().equals(shopId))
            {
                throw new RRException("只能停止自己店铺的优惠券");
            }
        }

        if(!CouponConstant.UseStatus.NORMAL.equals(couponEntity.getActiveState()))
        {
            throw new RRException("只有已发布正常状态下的优惠券才可以停止");
        }

        couponEntity.setStatus(CouponConstant.CouponStatus.STOP);
        this.modify(couponEntity);
    }

    @Override
    public void cancelStop(Long id, Long shopId) {
        CouponEntity couponEntity = this.loadById(id, true);
        if(CouponConstant.CouponMode.SHOP.equals(couponEntity.getMode()))
        {
            if(!couponEntity.getShopId().equals(shopId))
            {
                throw new RRException("只能停止自己店铺的优惠券");
            }
        }

        if(!CouponConstant.UseStatus.STOP.equals(couponEntity.getActiveState()))
        {
            throw new RRException("只有已停止状态下的优惠券才可以恢复");
        }

        couponEntity.setStatus(CouponConstant.CouponStatus.RELEASED);
        this.modify(couponEntity);
    }

    @Override
    public void cancelReleased(Long id, Long shopId) {
        CouponEntity couponEntity = this.loadById(id, true);
        if(CouponConstant.CouponMode.SHOP.equals(couponEntity.getMode()))
        {
            if(!couponEntity.getShopId().equals(shopId))
            {
                throw new RRException("只有取消发布自己店铺的优惠券");
            }
        }
        if(!CouponConstant.UseStatus.RELEASED.equals(couponEntity.getActiveState()))
        {
            throw new RRException("只有已发布还未开始的优惠券才可以取消发布");
        }

        couponEntity.setStatus(CouponConstant.CouponStatus.WAIT_RELEASE);
        this.modify(couponEntity);
    }


    private void batchAdaptShopOrGoods(CouponEntityDTO dto, CouponEntity couponEntity) {
        if(couponEntity.getMode().equals(CouponConstant.CouponMode.PLATFORM) && !dto.getUniversal())
        {
            List<CouponShopEntity> couponShopEntities = new ArrayList<>();
            for(Long shopId : dto.getAdaptShopIds())
            {
                CouponShopEntity couponShopEntity = new CouponShopEntity();
                ShopEntity shopEntity = shopService.loadShopBy(shopId, true);
                if(shopEntity.loadLockStatus())
                {
                    throw new RRException(String.format("店铺[%s]已被锁定",shopEntity.getShopName()));
                }
                couponShopEntity.setCouponId(couponEntity.getId());
                couponShopEntity.setShopId(shopId);
                couponShopEntities.add(couponShopEntity);
            }
            couponShopService.batchSet(couponEntity,couponShopEntities);
        }

        if(couponEntity.getMode().equals(CouponConstant.CouponMode.SHOP) && !dto.getUniversal())
        {

            List<CouponGoodsEntity> couponGoodsEntities = new ArrayList<>();
            for(Long goodsId : dto.getAdaptGoodsIds())
            {
                CouponGoodsEntity couponGoodsEntity = new CouponGoodsEntity();
                Goods goods = goodsService.getById(goodsId, true);
                if(!goods.getShopId().equals(couponEntity.getShopId()))
                {
                    throw new RRException("只能指定自己店铺的商品");
                }

                if(!GoodsConstant.VerifyStatus.YES.equals(goods.getVerifyStatus()))
                {
                    throw new RRException(String.format("商品[%s]没有通过审核",goods.getTitle()));
                }

                GoodsAuthShop goodsAuthShop = goods.loadPublishAuth();
                if(!goodsAuthShop.isAdded())
                {
                    throw new RRException(String.format("商品[%s]没有上架",goods.getTitle()));
                }

                couponGoodsEntity.setCouponId(couponEntity.getId());
                couponGoodsEntity.setGoodsId(goodsId);
                couponGoodsEntity.setShopId(couponEntity.getShopId());
                couponGoodsEntities.add(couponGoodsEntity);
            }
            couponGoodsService.batchSet(couponEntity,couponGoodsEntities);
        }
    }

    @NotNull
    private Integer computeAdaptActivity(CouponEntityDTO dto) {
        Integer adaptActivity  = 0;
        List<AdaptActivityVo> adaptActivityData = dto.getAdaptActivityData();
        for(AdaptActivityVo vo:adaptActivityData)
        {
            CouponConstant.ActivityCouponType type = CouponConstant.ActivityCouponType.getByCode(vo.getCode());
            if(ObjectUtils.isNull(type))
            {
                throw new RRException("适配的活动类型不存在");
            }
            adaptActivity = vo.getOn()?adaptActivity + CouponConstant.ADAPT_ACTIVITY.get(type):adaptActivity;
        }
        return adaptActivity;
    }

    private void validateMode(CouponEntityDTO dto) {
        CouponConstant.CouponMode byCode = CouponConstant.CouponMode.getByCode(dto.getMode());
        if(byCode.equals(CouponConstant.CouponMode.PLATFORM))
        {
            if(dto.getShopId()>0)
            {
                ShopEntity shopEntity = shopService.loadShopBy(dto.getShopId(), true);
                if(!shopEntity.getPlatformShop())
                {
                    throw new RRException("只有平台才能发布平台优惠券");
                }
                dto.setShopId(0L);
            }
            if(!dto.getUniversal() && CollectionUtil.isEmpty(dto.getAdaptShopIds()))
            {
                throw new RRException("如果是平台券，又不是通用券,一定要指定适合或不适合的店铺");
            }
        }

        if(byCode.equals(CouponConstant.CouponMode.SHOP) )
        {
            if(dto.getShopId()==0)
            {
                throw new RRException("店铺优惠券应存在发布店铺");
            }

            if(!dto.getUniversal() && CollectionUtil.isEmpty(dto.getAdaptGoodsIds()))
            {
                throw new RRException("如果是店铺券，又不是通用券,一定要指定适合或不适合的商品");
            }
        }
    }





    @Override
    public CouponEntity loadById(Long couponId, Boolean tw) {
        CouponEntity coupon = this.getById(couponId);
        if(tw && null == coupon)
        {
            throw new RRException(String.format("不存在编号为[%s]的优惠券",couponId.toString()));
        }
        return coupon;
    }

    @Override
    public CouponEntity loadByCode(String code, Boolean tw) {
        CouponEntity coupon = this.baseMapper.selectOne(new LambdaQueryWrapper<CouponEntity>().eq(CouponEntity::getCode,code).last("limit 1"));
        if(tw && null == coupon)
        {
            throw new RRException(String.format("不存在编号为[%s]的优惠券",code));
        }
        return coupon;
    }



    @Override
    public CouponEntityVo loadByCouponSlimEntity(Long couponId, Boolean tw) {
        CouponEntityVo vo = this.baseMapper.loadByCouponSlimEntity(couponId);
        if(tw && null == vo)
        {
            throw new RRException(String.format("不存在编号为[%s]的优惠券",couponId.toString()));
        }
        return vo;
    }

    @Override
    public List<CouponEntity> loadValidNewPerson() {
        Date now = new Date();
        return this.baseMapper.selectList(new LambdaQueryWrapper<CouponEntity>()
                .eq(CouponEntity::getTrait,1)
                .eq(CouponEntity::getStatus,2)
                .le(CouponEntity::getStartTime,now)
                .gt(CouponEntity::getEndTime,now)
        );
    }

    @Override
    public void batchRemoveByIds(List<Long> asList) {
        List<Long> errIds =  new ArrayList<>();
        for(Long id:asList)
        {
            CouponEntityVo couponEntityVo = this.loadByCouponSlimEntity(id, true);
            if(!CouponConstant.CouponStatus.WAIT_RELEASE.equals(couponEntityVo.getStatus()))
            {
                errIds.add(id);
                continue;
            }
            this.baseMapper.deleteById(id);
            couponGoodsService.getBaseMapper().delete(new LambdaQueryWrapper<CouponGoodsEntity>().eq(CouponGoodsEntity::getCouponId,id));
            couponShopService.getBaseMapper().delete(new LambdaQueryWrapper<CouponShopEntity>().eq(CouponShopEntity::getCouponId,id));
        }

        if(!CollectionUtil.isEmpty(errIds))
        {
            throw new RRException(String.format("编号为:%s 的优惠券活动已经开始,不能删除",StringUtils.join(errIds.toArray(),",")));
        }

    }



}
